#include<iostream>
#include "mytbf.h"
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#include<cstring>
#include<pthread.h>
#include<stdlib.h>
using namespace std;

struct mytbf_st{
    int pos; //在数组中的位置，最后是一个结构体数组
    int brust;
    int token;
    int cps;
    pthread_mutex_t mut; //互斥量和条件变量
    pthread_cond_t cond;
};

static mytbf_st * jobs[TBF_MAX]={NULL};

//给job数组配置锁，每次访问数组需要进行判断
static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER;
static pthread_once_t once_ctl = PTHREAD_ONCE_INIT;
static pthread_t init_pid;



int get_freepos_unlock(){
    for(int i=0;i<TBF_MAX;i++){
        if(jobs[i]==NULL){
            return i;
        }
    }
    return -1;
}

void* alrm_handler(void *){
    while(1){
        pthread_mutex_lock(&mut_job);
        for(int i=0;i<TBF_MAX;i++){
            if(jobs[i]!=NULL){

                pthread_mutex_lock(&jobs[i]->mut);
                jobs[i]->token+=jobs[i]->cps;

                if(jobs[i]->token>jobs[i]->brust)
                    jobs[i]->token = jobs[i]->brust;
                pthread_cond_broadcast(&jobs[i]->cond);
                // 因为增加了token，所以可以将正在阻塞的线程唤醒


                pthread_mutex_unlock(&jobs[i]->mut);
            }
        }
        pthread_mutex_unlock(&mut_job);
        usleep(1000000);
    }
}
void model_unload(){
    pthread_cancel(init_pid);
    pthread_join(init_pid,NULL);
    for(int i=0;i<TBF_MAX;i++){
        pthread_mutex_destroy(&jobs[i]->mut);
        pthread_cond_destroy(&jobs[i]->cond);

    }
}



void model_load(){
 
    pthread_create(&init_pid,NULL,alrm_handler,NULL); 
    // 注意：使用线程之后就可以不使用信号（最好不混用）
    //使用sleep或者usleep进行阻塞循环扫描，因为是创建了一个新线程，所以无所谓


}

mytbf_t* mytbf_init(int cps, int brust){ //cps 速率 ， brust 上限
    mytbf_st * me;

    pthread_once(&once_ctl,model_load);


    me = new mytbf_st; // 有问题
    if(me==NULL){
        return NULL;
    }
    me->cps = cps;
    me->brust = brust;
    me->token = 0;
    pthread_mutex_init(&me->mut,NULL);
    pthread_cond_init(&me->cond,NULL);
    
    //上锁，锁住jobs数组，不能冲突访问数组中的位置
    pthread_mutex_lock(&mut_job);
    me->pos = get_freepos_unlock();
    if((me->pos)<0){
        cout<<"error"<<endl;
        pthread_mutex_unlock(&mut_job); 
        // 注意这里要跳转函数，所以要解锁避免死锁
        delete me;
        return NULL;
    }
    jobs[me->pos] = me;
    //解锁
    pthread_mutex_unlock(&mut_job);
    return me;
}
int mytbf_destory(mytbf_t* tbf){
    mytbf_st *me = (mytbf_st*) tbf;
    pthread_mutex_lock(&mut_job);
    jobs[me->pos] = NULL;
    pthread_mutex_unlock(&mut_job);

    //接着将结构体中的资源进行一个一个释放
    pthread_mutex_destroy(&me->mut);
    pthread_cond_destroy(&me->cond);

    delete me;
    return 0;
}

int mytbf_returntoken(mytbf_t* tbf,int size){

    mytbf_st *me = (mytbf_st*)tbf;
    pthread_mutex_lock(&me->mut);
    me->token+= size;
    if(me->token>me->brust)
        me->token=me->brust;
    pthread_cond_broadcast(&me->cond); 
    // 还完token之后，可能是的其他被阻塞的线程可以正常执行
    // 所以需要唤醒其他线程
    pthread_mutex_unlock(&me->mut);
    return size;
}
int mytbf_gettoken(mytbf_t* tbf,int size){
    mytbf_st *me = (mytbf_st*) tbf;
    pthread_mutex_lock(&me->mut);
    while(me->token<=0){
        pthread_cond_wait(&me->cond,&me->mut);
    }
    int n = size>me->token?me->token:size;
    me->token -= n;
    pthread_mutex_unlock(&me->mut);
    return n;
}